package com.gzh.core.chche.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gzh.core.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @Author guanzh
 * @Date 2022/1/4 14:52
 * @Description
 */
@Slf4j
public abstract class Cache<T> implements ICache<T>{
    @Autowired
    private RedisTemplate redisTemplate;
    public String cacheKey;
    public String cacheName;

    public abstract String getKey(T t);

    //主体加载缓存逻辑
    public abstract Map<String, String> loadCacheData(List<String> keyList, String updateTime);

    public abstract List<T> getObjectListByKeyword(String findstr);

    public void init() {
        Long start = System.currentTimeMillis();
        log.debug("开始加载" + this.cacheName + "缓存");
        this.clear();
        Map<String, String> map = this.loadCacheData(new ArrayList<>(), "");
        this.addObjectList(map);
        log.debug("结束加载" + this.cacheName + "缓存,耗时: " + (System.currentTimeMillis() - start) + "ms");
    }

    //清空缓存数据
    public synchronized void clear() {
        if (redisTemplate.hasKey(cacheKey)) {
            redisTemplate.delete(cacheKey);
        }
    }

    //加载单项进缓存
    public synchronized void addObject(T t) {
        redisTemplate.opsForHash().put(cacheKey, getKey(t), JSONObject.toJSONString(t));
    }

    //加载数据列表
    public synchronized void addObjectList(Map<String, String> map) {
        redisTemplate.opsForHash().putAll(cacheKey, map);
    }

    //获取单笔数据
    public T getObject(String key) {
        Object obj = redisTemplate.opsForHash().get(cacheKey, key);
        T t;
        Type clazz = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        //没找到要从数据库中取一次
        if (obj == null) {
            Map<String, String> map = loadCacheData(Arrays.asList(key), "");
            if (CollectionUtils.isEmpty(map) || StringUtils.isEmpty(map.get(key))) {
                return null;
            }
            t = (T) JSON.parseObject(map.get(key), clazz);
            this.addObject(t);
        } else {
            t = (T) JSON.parseObject(obj.toString(), clazz);
        }
        return t;
    }

    //获取数据列表
    public List<T> getObjectList(List<String> keyList) {
        List<T> resultList = new ArrayList<>();
        Type clazz = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        if (!CollectionUtils.isEmpty(keyList)) {
            List<String> objectList = redisTemplate.opsForHash().multiGet(cacheKey, keyList);
            if (!CollectionUtils.isEmpty(objectList) && objectList.size() != resultList.size()) {
                for (int i = 0; i < keyList.size(); i++) {
                    T t = (T) JSON.parseObject(objectList.get(i), clazz);
                    if (!keyList.get(i).equals(this.getKey(t))) {
                        Map<String, String> map = loadCacheData(Arrays.asList(keyList.get(i)), "");
                        if(!CollectionUtils.isEmpty(map) && StringUtils.isNotEmpty(map.get(keyList.get(i)))){
                          T t1 = (T) JSON.parseObject(map.get(keyList.get(i)), clazz);
                          this.addObject(t1);
                          resultList.add(t1);
                        }else {
                          resultList.add(null);
                        }
                    } else {
                        resultList.add((T) JSON.parseObject(objectList.get(i), clazz));
                    }
                }
            }
        }
        return resultList;
    }

    //获取所有数据
    public List<T> getAllList() {
        List<T> resultList = new ArrayList<>();
        Type clazz = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        Map<String, String> objectMap = redisTemplate.opsForHash().entries(cacheKey);
        for (Map.Entry<String, String> entry : objectMap.entrySet()) {
            String jsonStr = entry.getValue();
            T item = JSON.parseObject(jsonStr, clazz);
            resultList.add(item);
        }
        return resultList;
    }
}
